home *** CD-ROM | disk | FTP | other *** search
/ Fritz: All Fritz / All Fritz.zip / All Fritz / FILES / PROGNG_C / SMALLC.LZH / SMALLC.DOC < prev    next >
Text File  |  1992-02-15  |  33KB  |  979 lines

  1.  
  2.  
  3.  
  4. I.  INTRODUCTION
  5.  
  6.     Welcome to Small-c:PC.  Small-c:PC is a compiler that runs
  7. under PC-DOS on the IBM Personal Computer (PC).  The source input
  8. to the compiler is written in small-c, a subset of the C
  9. programming language.  The compiler outputs symbolic assembly
  10. language code that can be assembled on the PC using the ASM or
  11. MASM assembler programs available from IBM.
  12.  
  13.     The reference manual for C is THE C PROGRAMMING LANGUAGE book
  14. published by Prentice-Hall and authored by Brian W.  Kernighan
  15. and Dennis M.  Ritchie.  The original compiler for Small-c was
  16. written by Ron Cain as a personal project (see Dr.  Dobb's
  17. Journal, #45, Volume V, Number 5 for a description of small-c).
  18. A CP/M version of the compiler for the Intel 8080 is being
  19. distributed by The Code Works, 5266 Hollister, Suite 224, Santa
  20. Barbara, California 93111 (805) 683-1585.
  21.  
  22.     After using the CP/M version of the compiler, we decided to
  23. port it over to the IBM PC (so we could take some of our small-c
  24. programs over with us).  The conversion effort was guided by a
  25. desire to not alter the personality of the original small-c
  26. compiler.  The objective was to minimize the effort required to
  27. convert existing small-c programs to the Small-c:PC environment.
  28. We think we have been successful since our small-c programs have
  29. been converted to the PC with few problems using Small-c:PC.
  30.  
  31.     The compiler was converted by first deciding what the output
  32. should look like and then modifying it to generate code for the
  33. Intel 8088 instead of the 8080.  In parallel, the run time
  34. library was rewritten in 8088 assembly language to operate under
  35. PC-DOS.  If you have The Code Works run time library for CP/M and
  36. are interested in the differences between CP/M and PC-DOS, you
  37. might take the time to compare our library with theirs.
  38.  
  39.     Most of the compiler conversion problems centered around
  40. ASM's need for memory.  The goal was to produce a tool that could
  41. be used on a 64KB PC with two 160KB drives.  Since ASM cannot
  42. deal with large programs in a 64 KB configuration, the small-c
  43. compiler was modified to produce code that could be assembled
  44. separately and then put together using LINK.  The original
  45. small-c compiler produces one large output file.  Small-c:PC can
  46. produce multiple output files (one for each input file).  These
  47. files can be assembled separately using ASM and then LINKed
  48. together.  This can significantly reduce program development
  49. time, however, since only the modified file need be recompiled in
  50. the event of source code changes.  It can then be assembled and
  51. linked with existing object files.
  52.  
  53.     If you have more than 64KB, ASM can assemble larger files.
  54. With sufficient memory, you can work with larger small-c program
  55.  
  56.  
  57.  
  58.                - 2 -
  59.  
  60.  
  61. files.    The memory requirement for using Small-c:PC, however, is
  62. imposed by ASM, not by the Small-c:PC compiler.  Small-c:PC will
  63. compile large programs quite nicely in 64KB.
  64.  
  65.     If you examine your distribution copy of the compiler, named
  66. CPCN.C, you will notice that the source code is marked so that it
  67. can be broken into many smaller files.    The makers are small-c
  68. comment statements written as:
  69.  
  70.                /* ### cpcn-xx */
  71.  
  72.     Each of these comment statements marks the start of a
  73. separate file.    We marked it this way so that users with only
  74. 64KB can modify the compiler if they choose to do so.  It will be
  75. necessary, however, to insert the proper external declarations
  76. into each file.  For those of you with more memory, it is a
  77. simple matter to generate a new version of the compiler after
  78. making any source editing changes.
  79.  
  80.     We have also distributed the source code for FORMAT, a text
  81. processor described in the book SOFTWARE TOOLS by Brian W.
  82. Kernighan and P.J.  Plauger and published by Addison-Wesley.
  83. This program is written in small-c.  This manual was produced
  84. using it.  The file FORMAT.DOC contains a brief description of
  85. the FORMAT program and how to use it.
  86.  
  87.     As a final note before we get into the operational details of
  88. the compiler you should be aware of the fact that it may contain
  89. bugs.  We have tested it quite a bit, but you know how those
  90. little rascals can hide.  So beware, one may sneak up and bite
  91. you (usually in the wee hours at the worst time).  If you find
  92. any of these critters, please write us and describe the problem.
  93. We have priced Small-c:PC to recover our development cost only.
  94. Please don't call us to discuss problems over the phone.
  95.  
  96.  
  97.  
  98.  
  99.                - 3 -
  100.  
  101.  
  102. II.  OPERATING Small-c:PC
  103.  
  104.     The compiler is initiated by entering CPC in response to the
  105. PC-DOS command prompt A>.  The compiler clears the screen, greets
  106. you and asks two questions.  The possible answers are contained
  107. in parenthesis following each question.  The capitalized response
  108. in the default taken if you press the ENTER key.  The first
  109. question asked is:
  110.  
  111.          Should I pause after an error (y,N)?
  112.  
  113.     Answering Y to this question causes the compiler to pause
  114. after displaying an error.  This will give you an opportunity to
  115. continue the compilation or not.  Moreover, in the event of a lot
  116. of screen activity during a compilation this insures that you
  117. won't miss an error message.  The N response causes the compiler
  118. to continue automatically after displaying an error.
  119.  
  120. The second question asked is:
  121.  
  122.     Do you want the Small-c:PC-text to appear (y,N)?
  123.  
  124.     Answering Y to this question causes the compiler to write the
  125. input source code into the output file(s) as comment statements.
  126. each small-c statement appears with a semicolon as the first
  127. character (to make it a comment to ASM) followed by the assembly
  128. language code generated by the compiler for that statement.  This
  129. interleaving of source code and generated code is very useful in
  130. learning how the compiler implements various small-c statements.
  131. Choosing this option causes the output files to be larger,
  132. however.  Answering N will cause the compiler to not write the
  133. small-c source to the output file.
  134.  
  135.     The two previous questions are followed by requests for input
  136. and output filenames.  There are no default extensions supplied
  137. by the compiler.  Each input file generates a separate output
  138. file.
  139.  
  140.     You can break a large small-c program into separate smaller
  141. files and feed these to the compiler.  Hopefully ASM will be able
  142. to swallow the resultant output files without running out of
  143. memory.  Again, if you have more than 64KB, ASM should be able to
  144. process a large output file.  In this case you will not be forced
  145. to divide a large small-c program into multiple files.
  146.  
  147. The next request by the compiler is?
  148.  
  149.                  Input filename?
  150.  
  151.     The small-c source code is contained in the file you name in
  152. response to this question.  There is no default extension supplied
  153.  
  154.  
  155.  
  156.                - 4 -
  157.  
  158.  
  159. by the compiler.
  160.  
  161.     A single function definition cannot be spread out across
  162. multiple input files.  This is because the compiler assumes the
  163. output file corresponding to each input file will be separately
  164. assembled.  It writes extra assembly language statements into
  165. each output file to support this.  A function spread across two
  166. input files may not assemble correctly.  Also, due to the way the
  167. compiler handles externals, it is possible that a function name
  168. could be multiply defined and the compiler not detect it.  This
  169. can happen if the separate definitions occur in different input
  170. files.    In this circumstance, the error will be detected by LINK.
  171.  
  172.     The runtime library (CPCLIB.ASM) is not input to the compiler
  173. as in other incarnations of small-c.  Instead, it is input to
  174. LINK as just another object file.  LINK will bind all of the
  175. object inputs together to produce an execute (.EXE) file.
  176.  
  177.     If your response to the input filename request is the ENTER
  178. key or a space (as the first character), the compiler terminates
  179. and returns control to PC-DOS.    This is the way the compiler is
  180. normally ended.
  181.  
  182. Following the input filename request is the question:
  183.  
  184.             Output filename?
  185.  
  186.     The assembly language generated by the compiler for the
  187. previous input file is written into the named file.  Normally
  188. this file will have the extension .ASM (not supplied
  189. automatically by the compiler) since it will be input to the
  190. assembler.  If you press ENTER instead of providing a file name,
  191. the compiler will direct its output to the display.  You might
  192. try this initially to get a feel for the code the compiler
  193. generates.
  194.  
  195.     Let's consider the interactions to compile a sample program.
  196. Suppose the program is broken into two files names "SAMPLE-1.C"
  197. and "SAMPLE-2.C".  You should first format a PC-DOS data disk and
  198. copy over to it the following files.
  199.  
  200. CPC.EXE     [from the Small-c:PC distribution disk]
  201. CPCLIB.OBJ              "
  202. SAMPLE-1.C              "
  203. SAMPLE-2.C              "
  204.  
  205. We assume the following files are on your system disk which is in
  206. drive A.
  207.  
  208. ASM.EXE     [from your IBM supplied macro assembler disk]
  209. LINK.EXE    [from your IBM supplied PC-DOS disk]
  210.  
  211.  
  212.  
  213.                - 5 -
  214.  
  215.  
  216. Note:  You could use MASM instead of ASM.
  217.  
  218. Get started by entering the following (the disk you made is in
  219. drive B) and drive B is the logged in disk.
  220.  
  221. B>CPC                      [invoke the compiler]
  222.  
  223. * * *  Small-C:PC  V1.1  * * *     [first line of a clear screen]
  224.  
  225. By Ron Cain, Modified by CAPROCK SYSTEMS for the IBM PC
  226.  
  227.  
  228. Distributed by:  CAPROCK SYSTEMS, INC>
  229.          P.O. Box 13814
  230.          Arlington, Texas 76013
  231.  
  232. PC-DOS Version N:  June, 1982
  233.  
  234.  
  235. Should I pause after an error (y,N)>?  Y      [You don't want
  236.                           to miss any]
  237.  
  238. Do you want the Small-c:PC-text to appear (y,N)?  N     [no]
  239.  
  240. Input filename?  SAMPLE-1.C
  241.  
  242. Output filename?  SAMPLE-1.ASM
  243. ====== main ()            [you know when it starts on a new
  244. ====== plc()            function]
  245.  
  246. There were 0 errors in compilation.
  247.  
  248. Input filename?  SAMPLE-2.C    [the program is stored in two
  249.                 separate files]
  250.  
  251. Output filename?  SAMPLE-2.ASM
  252. ====== getname()
  253.  
  254. There were 0 errors in compilation.
  255.  
  256. Input filename?  [press ENTER]
  257.  
  258.  
  259.  
  260.     Notice that the two input files could have been processed in
  261. separate executions of the compiler.  SAMPLE-2.C contains the
  262. necessary external data declarations to inform the compiler about
  263. referenced data allocated elsewhere.
  264.  
  265.      The output files are assembled next.
  266.  
  267.  
  268.  
  269.  
  270.                - 6 -
  271.  
  272.  
  273. B>A:ASM SAMPLE-1,,NUL:,NUL:
  274. B>A:ASM SAMPLE-2,,NUL:,NUL:
  275.  
  276.     Next, we want to produce an execute file.  You do this by
  277. executing LINK.  Our example assumes LINK inputs as required by
  278. PC-DOS Version 1.1.  If you have Version 2.0 your LINK inputs
  279. will be slightly different, but the results should be the same.
  280. The order of the object file names supplied to LINK is
  281. immaterial.
  282.  
  283. B>A:LINK SAMPLE-1+SAMPLE-2+CPCLIB,SAMPLE,NUL:,NUL:
  284.  
  285. They you are ready to execute the small-c program.  This is
  286. accomplished by typing the .EXE file name.
  287.  
  288. B>SAMPLE SAMPLE-1.ASM
  289.  
  290. The SAMPLE program provided on the distribution disk types a text
  291. file onto the display.    It obtains the file name to operate on
  292. from the command line.
  293.  
  294.  
  295. ERROR REPORTING
  296.  
  297.  
  298. When the compiler detects an error in the small-c program, it
  299. displays a message on the screen.  An example would be:
  300.  
  301. Line 20, main + 0: missing open paren
  302. main)
  303.      ^
  304.  
  305.  
  306.     The error occurred on the 20-th line in the input file.  The
  307. function being compiled was "main".  The error occurred 0 lines
  308. into the function.  the error detected was a "missing open
  309. paren".  The hat character (^) shows where the compiler was at
  310. character-wise when it detected the error.  The compiler
  311. continues automatically if you answered N to the first question
  312. asked by the compiler (see example above).  If you answered Y to
  313. this questions, you will see the following message displayed.
  314.  
  315.             Continue (Y,n,g)  ?
  316.  
  317. Pressing Y (or just ENTER) causes the compiler to continue
  318. processing the source input.  If you type N, the compiler
  319. displays the message
  320.  
  321.            Compilation aborted.
  322.  
  323. and returns to PC-DOS.    If you answer G, the compiler continues
  324.  
  325.  
  326.  
  327.                - 7 -
  328.  
  329.  
  330. processing the source input, but will no longer pause after an
  331. error.
  332.  
  333.     Pressing CTRL+BREAK at any time will abort the compiler and
  334. return you to PC-DOS.  If the compiler is terminated by
  335. CTRL+BREAK, no input or output files are closed.
  336.  
  337.  
  338.  
  339.  
  340.                - 8 -
  341.  
  342.  
  343. III.  USING THE LIBRARY FUNCTIONS
  344.  
  345.     All of the modules whose entry point names began with CC are
  346. used to support the compiler generated code.  As a user, you will
  347. probably never use these routines directly.  The functions that
  348. start with QZ are user callable.  They can be divided into PC-DOS
  349. interface routines and system interfact routines.  The PC-DOS
  350. interfact routines generally provide I/O through the operating
  351. system.  The disk I/O functions buffer only one 512 byte sector
  352. at a time (each open file has its own sector buffer space,
  353. however).  This combined with the fact that the transfer width
  354. between a small-c program and the disk routines is only one byte
  355. causes file I/O to be somewhat slow.  Also, the library routines
  356. support only ASCII files.  Certain characters are given special
  357. meanings.  AS a result, you can not manipulate binary files with
  358. small-c programs.  These file types include .OBJ, .EXE and .COM
  359. files.
  360.  
  361.  
  362.  
  363.  
  364.                - 9 -
  365.  
  366.  
  367. THE PC-DOS INTERFACE LIBRARY ROUTINES
  368.  
  369.  
  370.     The following presents examples to illustrate the PC-DOS
  371. interface routines.  The small-c declarations are simply
  372. illustrations of what can be done.  There are myriad ways to
  373. accomplish the same coding example.  The PC-DOS function numbers
  374. mentioned in the descriptions are given in decimal.
  375.  
  376.            int c;
  377.            char buffer[81];
  378.            char *name,*mode;
  379.            int *ptr;
  380.            int ax,ah,dx;
  381.            char *string;
  382.  
  383.  
  384. 1.  Read a character from the keyboard.
  385.  
  386.                c = getchar();
  387.  
  388.     Reads a character from the keyboard using PC-DOS function 1.
  389. The character read is echoed back to the display.  Extended ASCII
  390. codes will require two calls to this function.    A second call is
  391. indicated if the returned character is null.  If the character
  392. input is a carriage return, a line feed is also echoed back to
  393. the display.  If the character is CTRL-Z, a -1 is returned
  394. instead.
  395.  
  396. 2.  Write a character to the display.
  397.  
  398.                c = putchar(c);
  399.  
  400.     The character in the low order byte of c is written to the
  401. display using PC-DOS function 2.  Refer to appendix G of the
  402. BASIC manual to determine the effect of each possible character
  403. code.  If the character passed is a carriage return, a line feed
  404. is also sent to the display.  This function returns the character
  405. passed to it.
  406.  
  407. 3.  Read a line from the keyboard.
  408.  
  409.                 gets(buffer);
  410.  
  411.     Reads one line of characters into the character array buffer
  412. using PC-DOS function 10 for buffered keyboard input.  Editing of
  413. the buffer during character entry is supported by PC-DOS (see
  414. chapter 1 of the DOS manual).  A null character is placed at the
  415. end of the line (replaces the usual carriage return at the end of
  416. the line).  Note:  the buffer is assumed to be at least 80 bytes
  417. in length.
  418.  
  419.  
  420.  
  421.                - 10 -
  422.  
  423.  
  424. 4.  Print a line on the display.
  425.  
  426.                 puts(buffer);
  427.  
  428.     Each character of the buffer is written to the display using
  429. PC-DOS function 2 (display character).    Refer to appendix G of
  430. the BASIC manual to see how the character codes are interpreted.
  431. Characters are sent to the display until a null character is
  432. encountered.  The null character is not sent to the display.  No
  433. carriage return or line feed is automatically sent to the
  434. display.
  435.  
  436. 5.  Open a disk file for processing.
  437.  
  438.                 ptr = fopen(name,mode);
  439.  
  440.     The named file is opened for processing using DOS function
  441. 15.  The name is parsed using DOS function 41 before the open
  442. call.  The mode determines how the file is opened.  An "r" or "R"
  443. opens it for input and "w" or "W" opens it for output.  Notice
  444. that mode is a pointer to a string.  The string contains the
  445. character indicating the desired mode.    No error checks are made.
  446. The pointer returned is an offset into the library data segment
  447. of an I/O structure.  The structure consists of the FCB followed
  448. by the sector buffer (see CPCLIB data segment).  This pointer
  449. must be passed to functions getc, putc and fclose described
  450. below.    If the open fails, a zero is returned to ptr.  The open
  451. can fail for a variety of reasons.  No more than four files may
  452. be open at one time.  So lack of an available I/O structure can
  453. cause failure.    The filename supplied could be in error or not
  454. exist.    It could be that the mode indicated is not one of the
  455. four possible characters indicated above.  Programming note:  to
  456. test if a file exists before opening it for output, first open it
  457. for input.  If this open is successful the file exists.
  458.  
  459. 6.  Close a disk file.
  460.  
  461.                 fclose(ptr);
  462.  
  463.     The file described by the I/O structure indicated by ptr is
  464. closed to further processing.  Any unwritten characters in the
  465. sector buffer are written to disk first.  No error check is made
  466. on the value in ptr.  The function returns a zero if the close
  467. fails.    It returns a non-zero value if the close is successful.
  468. Note that files are not automatically closed when the program
  469. exits.
  470.  
  471. 7.  Read the next character from an opened disk file.
  472.  
  473.                 c = getc(ptr);
  474.  
  475.  
  476.  
  477.  
  478.                - 11 -
  479.  
  480.  
  481.     The next unread character is returned.  The ptr is the I/O
  482. structure offset returned by fopen.  The file is assumed to be a
  483. text file.  When a carriage return is read, the character that
  484. immediately follows the carriage return is presumed to be a line
  485. feed and is discarded automatically.  (No check is made to verify
  486. that it was a line feed).  When a CTRL-Z or a physical
  487. end-of-file is detected, a -1 is returned.  A read error also
  488. returns a -1.
  489.  
  490. 8.  Write a character to an opened disk file.
  491.  
  492.                 c = putc(c,ptr);
  493.  
  494.     The character is buffered into the sector buffer indicated by
  495. the ptr (see fopen).  If the character is a carriage return, a
  496. line feed is automatically buffered.  A physical disk write
  497. occurs when the sector buffer is filled.  This function returns
  498. the argument character if no error occurs.  A -1 is returned if
  499. an error occurs.
  500.  
  501. 9.  Call to PC-DOS.
  502.  
  503.                 ax = pcdos(ah,dx);
  504.  
  505.     This function calls PC-DOS.  The low order byte of the first
  506. argument is placed into the AH register.  The second argument is
  507. placed into the DX register.  PC-DOS returns a value in the AX
  508. register.  This value is stored into the variable ax as
  509. indicated.
  510.  
  511.     This function is useful for supporting I/O to the printer or
  512. communications device.    The following function sends the passed
  513. character to the printer.
  514.  
  515.           listchar(c)
  516.            char c;
  517.           {
  518.            pcdos(5,c);
  519.            return (c);
  520.           }
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527.                - 12 -
  528.  
  529.  
  530. THE SYSTEM INTERFACE LIBRARY ROUTINES
  531.  
  532.  
  533.     Like those used above, the following additional declarations
  534. are made to illustrate usage of the system interface library
  535. routines.  These routines generally provide access to the
  536. hardware on the PC or to special software elements of the system.
  537.  
  538.            int port,ah,al,bh,bl,ch,cl,dh,dl;
  539.            char string[256];
  540.            int val;
  541.  
  542.     Some of the declared names refer to 808x registers.  When the
  543. name of an 8-bit register appears as an argument in the examples
  544. below, the low order byte of the value passed is copied into the
  545. 808x register with the same name to execute the function
  546. indicated.  If a 16-bit register is designated, the full 16-bit
  547. argument is loaded into the 808x register with the same name.
  548.  
  549. 1.  Send a byte to a physical output port.
  550.  
  551.                 out808x(port,al);
  552.  
  553.     The low order byte of the second argument is sent to the
  554. hardware port address indicated by the first argument.    No value
  555. is returned.  Refer to the PC Technical Reference Manual for a
  556. description of the physical I/O ports on the PC.
  557.  
  558. 2.  Input a byte from a physical input port.
  559.  
  560.                 val = in808x(port);
  561.  
  562.     An IN instruction is executed using the hardware port address
  563. provided by the argument.  The byte read is sign extended and
  564. returned as a 16-bit value.  Refer to the PC Technical Reference
  565. Manual for a description of the physical I/O ports on the PC.
  566.  
  567. 3.  Display control through the PC rom BIOS.
  568.  
  569.              int10(ah,al,bh,bl,ch,cl,dh,dl);
  570.  
  571.     PC-DOS does not support complete display capabilities as
  572. provided on the PC.  This function allows the small-c programmer
  573. control over the display as supported by the rom BIOS routines.
  574. The PC Technical Reference Manual contains a description in the
  575. rom listings of the required parameter values.    Certain functions
  576. may not require all of the argument registers.    A dummy argument
  577. must be provided, however, since the library routine expects all
  578. of the indicated arguments (it is not function sensitive).
  579.  
  580. 4.  Control and I/O through the asynchronous port.
  581.  
  582.  
  583.  
  584.  
  585.                - 13 -
  586.  
  587.  
  588.             ax = int14(ah,al,dx);
  589.  
  590.     Support of the async adapter through PC-DOS is not complete
  591. (especially on status information).  This function allows the
  592. small-c programmer greater control over the comm port.    Again,
  593. the ROM listings in the PC Technical Reference Manual contain a
  594. complete description of the parameters for this function.
  595.  
  596. 5.  Sound the bell.
  597.  
  598.                  bell();
  599.  
  600.     This function simply calls PC-DOS to display the bell
  601. character code.
  602.  
  603. 6.  Clear the display buffer (and hence the display screen).
  604.  
  605.                 clrscreen();
  606.  
  607.     This is essentially a clear screen function as provided on
  608. many dumb terminals.  This function illustrates how the PC
  609. programmer may manipulate the display memory directly to manage
  610. the display.
  611.  
  612. 7.  Copy code segment prefix into a small-c data array.
  613.  
  614.               copyprefix(string);
  615.  
  616.     The program prefix as described in the DOS manual contains
  617. information that may be useful to the small-c programmer.  For an
  618. example, study the sample program provided on the distribution
  619. disk.  This function copies all 256 bytes of the prefix into
  620. string.  Using appropriate offsets (or subscripts), the contents
  621. of the prefix area can be examined.
  622.  
  623. 8.  Exit to PC-DOS.
  624.  
  625.                   exit();
  626.  
  627.     This is the function to use in exiting a small-c program at a
  628. point other than a normal return from the main() function.  The
  629. exit function assumes that the DS and SS registers are unchanged
  630. from their contents at program entry.
  631.  
  632.  
  633.  
  634.  
  635.                - 14 -
  636.  
  637.  
  638. IV.  ASSEMBLY LANGUAGE INTERFACE
  639.  
  640.     Some remaining portions of this manual are reproduced from
  641. the user manual for the small-c compiler distributed by The Code
  642. Works.    Interfacing to assembly language is accomplished in two
  643. ways.  As the library routines demonstrate, you can simply code a
  644. module in the code segment CSEG, assemble it and LINK will
  645. resolve the call if the function name is made PUBLIC.  You can
  646. build your own assembly language library to LINK with small-c
  647. programs that you write.
  648.  
  649.     The compiler also supports a language construct that permits
  650. in-line assembly language code to be directly inserted into the
  651. generated output file.    This language construct is the
  652. #asm...#endasm statements.  Like all preprocessor commands, #asm
  653. and #endasm must be entered in lower case.  Since it is
  654. considered by the compiler to be a single statement, it may
  655. appear any where a statement is needed.  For example,
  656.  
  657.           while(...) #asm...#endasm
  658.  
  659.           or
  660.  
  661.           if(...) #asm...#endasm else ...
  662.  
  663.     Due to the workings of the preprocessor (which must be
  664. suppressed by this construct), the pseudo-op #asm must be the
  665. last item before the carriage return on the end of the line
  666. (since the text between #asm and the carriage return is thrown
  667. away).    The parser is free-format (outside of these exceptions).
  668. So the expected format is as follows:
  669.  
  670.         if (...) #asm         [nothing following #asm]
  671.             ...
  672.             ...
  673.             #endasm
  674.         else statement;
  675.  
  676. A semicolon is not required after the #endasm.
  677.  
  678.     Assembly language code within the #asm...#endasm context can
  679. access all global variables and functions by name.  It is up to
  680. the programmer to know the data type of a variable (i.e.  whether
  681. to access a byte or a word).  Global variables should be accessed
  682. relative to the stack segment as opposed to the data segment.  To
  683. store the AX register into the variable named intvar, code
  684.  
  685.                 MOV SS:QZINTVAR,AX
  686.  
  687.     All global variables and function names have a 'QZ' prefix
  688. added by the compiler.    This is illustrated above.  As another
  689.  
  690.  
  691.  
  692.  
  693.                - 15 -
  694.  
  695.  
  696. illustration, to call putchar() in an assembler routine, code
  697. CALL QZPUTCHAR.  Since the library is not assembled with the
  698. generated code, it is necessary to tell the assembler that a
  699. library name is external.  Insert the statement
  700.  
  701.             EXTRN      QZPUTCHAR:NEAR
  702.  
  703. in your assembly language code.  If putchar() is called by the
  704. small-c code containing your assembler code, then you do not need
  705. to insert the EXTRN statement.    The compiler will generate one
  706. for the reference in the small-c code.    A similar situation
  707. exists for global data items.  For instance, if intvar is not
  708. defined (or referenced) by containing small-c code, it will be
  709. necessary to code
  710.  
  711.             EXTRN QZINTVAR:NEAR
  712.  
  713. For other illustrations of this, refer to the generated code for
  714. the sample program on the distribution disk to see how the
  715. compiler handles similar references.
  716.  
  717.     External assembly language routines invoked by function calls
  718. from the small-c code have access to all registers.  However, the
  719. DS and SS (and naturally CS) must be preserved across the
  720. assembly language code.  All other registers can be altered
  721. without restoration.  The calling program removes arguments from
  722. the stack upon return.    The function should not prune the stack
  723. itself.
  724.  
  725.  
  726.  
  727.  
  728.  
  729.  
  730.                - 16 -
  731.  
  732.  
  733. RUN TIME CODE STRUCTURE AND SEGMENT USAGE
  734.  
  735.  
  736.     The compiler generates three segments as a result of
  737. processing the user's small-c program.  Executable code is placed
  738. in segment CSEG with a class 'code'.  Data items are stored in
  739. the segment STACK with the class 'stack'.  No information is
  740. stored in generated segment DUMMY.  It is produced to avoid a
  741. LINK error message.  The run time library makes use of a data
  742. segment DATASEG also in the class 'code'.  The LINK program
  743. combines all output files with specified libraries to produce the
  744. executable module.  This module, when loaded into memory, has the
  745. segments in class 'code' first followed by the stack segment
  746. whose class is 'stack'.  The entry point is CCGO in the run time
  747. library.  Routine CCGO loads the stack segment register and sets
  748. the stack pointer SP to the highest possible value.  It pushes
  749. information necessary to return to DOS onto the stack, then calls
  750. the user's main() function.  The exit() routine is entered either
  751. by a call from the user program or upon a return from main().
  752. The function exit() cleans the stack off up to the information
  753. placed there by CCGO.  It then does a long return to DOS.
  754.  
  755.     During execution, the stack is used extensively.  Function
  756. arguments are placed onto the stack in their textual order (left
  757. to right).  This is illustrated below by the code generated for
  758. the following statement.
  759.  
  760.           function(x,y,z,());
  761.  
  762.           MOV      BX,SS:QZX
  763.           PUSH      BX
  764.           MOV      BX,SS:QZY
  765.           PUSH      BX
  766.           CALL      QZZ
  767.           PUSH      BX
  768.           CALL      QZFUNCTION
  769.           POP      CX
  770.           POP      CX
  771.           POP      CX
  772.  
  773. Notice that the compiler generated code to clean up the stack.
  774.  
  775. Local variables are allocated onto the stack.  The current value
  776. of SP thus becomes their address.  For example, inside a
  777. function, the statement:
  778.  
  779.                  int k;
  780.  
  781. generates the code PUSH CX to occupy two bytes on the stack.
  782. References to the value k use the current value of SP.    If
  783. another value is defined, such as:
  784.  
  785.  
  786.  
  787.                - 17 -
  788.  
  789.  
  790.               char array[3];
  791.  
  792. the compiler would generate
  793.  
  794.         DEC    SP
  795.         PUSH    CX
  796.  
  797. to reserve three bytes on the stack.  The offset of array is the
  798. current value of SP.  So array[0] is at SP+0, array[1] at SP+1,
  799. array[2] at SP+2, and k would now be at SP+3.  Thus, assembly
  800. language code in the statement #asm...#endasm cannot access local
  801. variables by name.  They can be accessed by knowing how many
  802. intervening bytes have been allocated between the declaration of
  803. the variable and its use.  It is worth noting that local
  804. declarations use only as much stack space as required, including
  805. an odd number of bytes.  However, function arguments always
  806. consist of two bytes apiece.  If a function argument is of type
  807. char (one byte), the it is sign extended to obtain a 2 byte value
  808. to push onto the stack.
  809.  
  810.  
  811.  
  812.  
  813.                - 18 -
  814.  
  815.  
  816. Appendix A:  Small-c:PC COMPILER SPECIFICATION
  817.  
  818. The compiler supports the following.
  819.  
  820. 1.  Data type declarations can be:
  821.  
  822.          char             8-bits
  823.          int             16-bits
  824.          extern char         external 8-bits
  825.          extern int         external 16-bits
  826.          extern          external 16-bits
  827.  
  828. A pointer to either of these types is declared by placing an
  829. asterisk "*" before the pointer name.  A pointer is a 16-bit
  830. stack offset.
  831.  
  832. 2.  Arrays must be single dimension (vector) structures of type
  833. char or int.
  834.  
  835. 3.  Expressions:
  836.      unary operators:
  837.          "-"     minus
  838.          "*"     indirection
  839.          "&"     address of scalar
  840.          "++"    increment, either prefix or postfix
  841.          "--"    decrement, either prefix or postfix
  842.  
  843.      binary operators:
  844.          "+"     addition
  845.          "-"     subtraction
  846.          "*"     multiplication
  847.          "/"     division
  848.          "%"     mod, i.e. remainder from division
  849.          "|"     inclusive or
  850.          "^"     exclusive or
  851.          "&"     logical and
  852.          "=="    test for equality
  853.          "!="    test for inequality
  854.          "<"     test for less than
  855.          "<="    test for less or equal
  856.          ">"     test for greater than
  857.          ">="    test for greater or equal
  858.          "<<"    arithmetic shift left
  859.          ">>"    arithmetic shift right
  860.          "="     assignment
  861.  
  862.       primaries:
  863.          array[expression]
  864.          function(arg1,...,argn)
  865.          constants:
  866.              decimal number
  867.  
  868.  
  869.  
  870.                - 19 -
  871.  
  872.  
  873.              quoted string ("sample")
  874.              primed string ('a' or '10')
  875.          local variable (or pointer)
  876.          global (static) variable (or pointer)
  877.  
  878. 4.  Program control:
  879.  
  880.          if(expression) statement;
  881.          if(expression) statement;
  882.              else statement;
  883.          while (expression) statement;
  884.          break;
  885.          continue;
  886.          return;
  887.          return expression;
  888.          ; (null statement)
  889.          compound statement:
  890.          {statement1; statement2;...;statementn;}
  891.  
  892. 5.  Pointers
  893.  
  894.          local and static pointers can contain the
  895. address of "char" or "int" data items.
  896.  
  897. 6.  Compiler commands:
  898.  
  899.      #define name string
  900.          (preprocessor will replace name by string
  901. throughout the program text)
  902.      #include filename
  903.           (Input is suspended from the input filename and
  904. text is read from the file named in the include statement.  When
  905. end-of-file is detected, input is resumed from the input
  906. filename.  A separate output file is not created for the #include
  907. file.  Its output is directed to the currently open output file.)
  908.      #asm
  909.           (see section IV for description)
  910.  
  911. 7.  Miscellaneous notes:
  912.  
  913. Expression evaluation maintains the same hierarchy as standard C.
  914.  
  915. Function calls are defined as any primary followed by an open
  916. parenthesis.  Legal forms include:
  917.  
  918.           variable();
  919.           array[expression]();
  920.           constant();
  921.           function() ();
  922.  
  923. NOTE:  the various function call forms are not supported in
  924. standard C.
  925.  
  926.  
  927.  
  928.  
  929.                - 20 -
  930.  
  931.  
  932. Pointer arithmetic takes into account the data type the pointer
  933. was declared for (e.g. ptr++ will increment by 2 if declared
  934. "int *ptr;").
  935.  
  936. Pointers are compared as unsigned 16-bit values.
  937.  
  938. The generated code is pure.  Data is separated from executable
  939. code.
  940.  
  941. The generated code is reentrant.  Since local variables are
  942. allocated on the stack, each new invocation of a function
  943. generates a new copy of local variables.
  944.  
  945.  
  946.  
  947.  
  948.                - 21 -
  949.  
  950.  
  951. Appendix B:  COMPILER RESTRICTIONS AND LIMITATIONS
  952.  
  953. The compiler does not support:
  954.  
  955. 1.  Structures and unions
  956.  
  957. 2.  Multi-dimensional arrays
  958.  
  959. 3.  Floating point data
  960.  
  961. 4.  Long integers
  962.  
  963. 5.  Functions that return anything but "int" values
  964.  
  965. 6.  Unary operators "!", "~", "sizeof", casts
  966.  
  967. 7.  The operators "&&", "||", "?:", and ","
  968.  
  969. 8.  Assignment operators:
  970.  
  971.      +=, -=, *=, /=, %=, >>=, <<=, &=, ^=,
  972.  
  973. asts
  974.  
  975. 7.  The operators "&&", "||", "?:", and ","
  976.  
  977. 8.  Assignment operators:
  978.  
  979.      +=, -=, *=, /=, %